﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using umbraco.BusinessLogic;

namespace umbraco.DataServices.Linq {

    public class UmbracoContextFactory : ApplicationBase {

        private static UmbracoContextFactory _instance; //Singleton
        static readonly object _padlock = new object();

        private Dictionary<PropertyIdentifier, Type> _propertyRegistration;
        private IDocumentTypeSignatureCollection _propertySignatures;
        private bool _useLegacyXmlSchema;
        

        private UmbracoContextFactory() {
            Refresh();
        }

        public static UmbracoContextFactory Instance
        {
            get
            {
                lock (_padlock) {
                    if (_instance == null)
                        _instance = new UmbracoContextFactory();
                    return _instance;
                }
            }
        }

        public void Refresh() {
            lock (_padlock) {
                FindSchemaVersion();
                CreateInheritanceTree();
                CreatePropertySignatures();
            }
        }

        protected void CreateInheritanceTree() {
            //Get Signatures From Database
            var inheritanceBuilder = new InheritanceBuilder();
            _propertySignatures = inheritanceBuilder.Create();
        }

        protected void CreatePropertySignatures() {
            //Build Type Lookup
            _propertyRegistration = new Dictionary<PropertyIdentifier, Type>();
            foreach (var documentType in _propertySignatures) {
                var allInheritedDocuments = _propertySignatures.GetParentDocumentTypes(documentType);
                var documentTree = allInheritedDocuments.Union(new[] { documentType }); //Add Current
                foreach (var item in documentTree.SelectMany(p => p.Properties)) {
                    _propertyRegistration.Add(new PropertyIdentifier(documentType.Id, item.Alias), item.Type);
                }
            }
        }

        public void FindSchemaVersion() {
            _useLegacyXmlSchema = UmbracoSettings.UseLegacyXmlSchema;
        }

        public Dictionary<PropertyIdentifier, Type> PropertyRegistration
        {
            get { return _propertyRegistration; }
        }

        public IDocumentTypeSignatureCollection PropertySignatures {
            get { return _propertySignatures; }
        }

        public bool UseLegacyXmlSchema {
            get { return _useLegacyXmlSchema; }
        }

        public XDocument GetXmlDataSource() {
            if (HttpContext.Current == null)
                throw new Exception("AspNetCompatibility Is Required, Set In Web.Config (configuration/system.serviceModel/serviceHostingEnvironment/@aspNetCompatibilityEnabled=true)");
            if (presentation.UmbracoContext.Current == null)
                throw new Exception("UmbracoContext Not Initialised");
            var doc = presentation.UmbracoContext.Current.Server.ContentXml;
            if (doc != null)
                return doc;
            var path = presentation.UmbracoContext.Current.Server.ContentXmlPath;
            if (string.IsNullOrEmpty(path))
                throw new Exception("XML Is Not Loaded Into Cache, And XML Path Is Not Defined");
            return XDocument.Load(path);
        }

        public UmbracoContext CreateContext() {
            lock (_padlock) {
                if (UseLegacyXmlSchema)
                    return new UmbracoContext(GetXmlDataSource(), _propertyRegistration, _propertySignatures, new Schema.LegacySchema()); //Use Old /node
                return new UmbracoContext(GetXmlDataSource(), _propertyRegistration, _propertySignatures, new Schema.DefaultSchema()); //alias/alias
            }
        }

    }
}
